/* **********************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This source code is subject to terms and conditions of the Shared Source License
* for DSL Editor PowerToy. A copy of the license can be found in the License.htm file
* at the root of this distribution. If you can not locate the Shared Source License
* for DSL Editor PowerToy, please obtain a copy from: http://www.codeplex.com/dsltreegrideditor/Project/License.aspx.
* By using this source code in any fashion, you are agreeing to be bound by
* the terms of the Shared Source License for DSL Editor PowerToy.
*
* You must not remove this notice, or any other, from this software.
*
* **********************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Text;
using VSTrid = Microsoft.VisualStudio.VirtualTreeGrid;
using System.Reflection;
using System.Windows.Forms;

namespace DslEditorPowerToy.Controls.VirtualTreeGrid.Branches
{
    /// <summary>
    /// This class encapsulates and extends a PropertyDescriptor
    /// (ReferPropertyDescriptor) for static metadata description
    /// or Other Descriptor class if provided by type instance
    /// Since we cannot inherit from this specific class, 
    /// and we can't implement specific PropertyDescriptor abstract class, we use encapulation.
    /// </summary>
    public class ColumnDescriptor : PropertyDescriptor
    {
        PropertyDescriptor _descriptor = null;

        #region Constructors
        internal ColumnDescriptor(PropertyDescriptor descriptor)
            : base(descriptor)
        {
            this._descriptor = descriptor;
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Returns the text used in the column header
        /// </summary>
        public string ColumnHeaderText
        {
            get
            {
                Attribute attribute = this.Attributes[typeof(ColumnHeaderAttribute)];
                if (null != attribute)
                    return ((ColumnHeaderAttribute)attribute).Text;
                else
                    return string.Empty;
            }
        }
        /// <summary>
        /// Returns the order of the header
        /// </summary>
        public int ColumnOrder
        {
            get
            {
                Attribute attribute = this.Attributes[typeof(ColumnHeaderAttribute)];
                if (null != attribute)
                    return ((ColumnHeaderAttribute)attribute).Order;
                else
                    return 0;
            }
        }
        #endregion

        #region Overriden Public Methods
        /// <summary>
        /// Returns the type editor host for the propertyDescriptor
        /// </summary>
        internal VSTrid.TypeEditorHost GetEditorHost(object component)
        {
            //return TypeEditorHost.Create(this._descriptor, component);
            VSTrid.TypeEditorHost typeEditor = VSTrid.TypeEditorHost.Create(this, component);

            //BUGFIX: Bug in TypeEditorHostListBox:ctor() that calls GetStandardValues(null) on the typeconverter
            //For type converters that depend on the context of GetStandardValues(), 
            //the TypeConverter in this ctor() will not return correct values. 
            //So this fix, re-calls the method and populates the list editor again using a valid context
            if (typeEditor is VSTrid.TypeEditorHostListBox)
            {
                VSTrid.TypeEditorHostListBox editor = (VSTrid.TypeEditorHostListBox)typeEditor;
                ITypeDescriptorContext context = (ITypeDescriptorContext)typeEditor;
                if ((null != this.Converter)
                    && (true == this.Converter.GetStandardValuesSupported(context)))
                {
                    TypeConverter.StandardValuesCollection values = this.Converter.GetStandardValues(context);
                    if (null != values)
                    {
                        editor.Items.Clear();
                        foreach (object value in values)
                            editor.Items.Add(value);
                    }
                }
            }

            return typeEditor;
        }
        /// <summary>
        /// Determines if the provided value is valid for the propertyDescriptor,
        /// using the TypeConverter for the propertyDescriptor property (if any),
        /// else returns true
        /// </summary>
        /// <param name="value"></param>
        /// <returns>TypeConvert.IsValid(), else true if no TypeConverter for this property</returns>
        internal bool IsValid(object value)
        {
            //Validate using TypeConverter (if defined).
            if (null != this.Converter)
                return this.Converter.IsValid(value);
            else
                return true;
        }
        /// <summary>
        /// Gets the display value for the property
        /// </summary>
        /// <param name="component"></param>
        /// <returns></returns>
        public override object GetValue(object component)
        {
            //Get the display value's type (always string for the control)
            Type valueType = typeof(string);

            //Get the raw value
            object value = this._descriptor.GetValue(component);
            object displayValue = value;

            //Check if TypeConverter
            if (null != this.Converter)
            {
                //Check if type is convertable
                if (true == this.Converter.CanConvertTo(valueType))
                {
                    //Convert value to display value
                    displayValue = this.Converter.ConvertTo(value, valueType);
                }
            }

            return displayValue;
        }
        /// <summary>
        /// Sets the value of the property
        /// </summary>
        /// <param name="component"></param>
        /// <param name="value"></param>
        public override void SetValue(object component, object value)
        {
            //Check not readonly
            if (true == this.IsReadOnly)
                return;

            //Get the value's type
            Type valueType = value.GetType();
            object convertedValue = value;

            //Check if TypeConverter
            if (null != this.Converter)
            {
                //Validate using converter
                if (false == this.IsValid(value))
                    return;

                //Check if type is convertable
                if (true == this.Converter.CanConvertFrom(valueType))
                {
                    //Convert value
                    convertedValue = this.Converter.ConvertFrom(value);
                }
            }

            //Set the converted value
            this._descriptor.SetValue(component, convertedValue);
        }
        #endregion

        #region Delegations to Encapsulated Descriptor
        public override bool IsReadOnly
        {
            get
            {
                return this._descriptor.IsReadOnly;
            }
        }
        public override bool IsLocalizable
        {
            get
            {
                return this._descriptor.IsLocalizable;
            }
        }
        public override bool IsBrowsable
        {
            get
            {
                return this._descriptor.IsBrowsable;
            }
        }
        public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
        {
            return this._descriptor.GetChildProperties(instance, filter);
        }
        public override string DisplayName
        {
            get
            {
                return this._descriptor.DisplayName;
            }
        }
        public override bool DesignTimeOnly
        {
            get
            {
                return this._descriptor.DesignTimeOnly;
            }
        }
        public override string Description
        {
            get
            {
                return this._descriptor.Description;
            }
        }
        public override string Category
        {
            get
            {
                return this._descriptor.Category;
            }
        }
        public override bool SupportsChangeEvents
        {
            get
            {
                return this._descriptor.SupportsChangeEvents;
            }
        }
        public override void RemoveValueChanged(object component, EventHandler handler)
        {
            this._descriptor.RemoveValueChanged(component, handler);
        }
        public override AttributeCollection Attributes
        {
            get
            {
                return this._descriptor.Attributes;
            }
        }
        public override object GetEditor(Type editorBaseType)
        {
            return this._descriptor.GetEditor(editorBaseType);
        }
        public override string Name
        {
            get
            {
                return this._descriptor.Name;
            }
        }
        public override void AddValueChanged(object component, EventHandler handler)
        {
            this._descriptor.AddValueChanged(component, handler);
        }
        public override TypeConverter Converter
        {
            get
            {
                return this._descriptor.Converter;
            }
        }
        public override Type ComponentType
        {
            get
            {
                return this._descriptor.ComponentType;
            }
        }
        public override Type PropertyType
        {
            get
            {
                return this._descriptor.PropertyType;
            }
        }
        public override bool CanResetValue(object component)
        {
            return this._descriptor.CanResetValue(component);
        }
        public override void ResetValue(object component)
        {
            this._descriptor.ResetValue(component);
        }
        public override bool ShouldSerializeValue(object component)
        {
            return this._descriptor.ShouldSerializeValue(component);
        }
        #endregion
    }
}